
#include "Core.hpp"
#include "Exception.hpp"
#include "FullscreenManager.hpp"
#include "MaterialManager.hpp"
#include "Shader.hpp"
#include "Texture.hpp"
#include "Adapter.hpp"

namespace VoodooShader
{
	Core::Core(std::string logfile)
		: mAdapter(NULL)
	{
		this->mLogger = new Logger(logfile.c_str());
#ifdef _DEBUG
		this->mLogger->SetBufferSize(0);
#endif
		this->mLogger->Log("Voodoo Core: Preparing core components...\n");

		// Init Cg
		this->mCGContext = cgCreateContext();

		if ( !cgIsContext(this->mCGContext) )
		{
			Throw("Voodoo Core: Could not create Cg context.", this);
		}

		cgSetErrorHandler(&(Core::CGErrorHandler), this);

		this->mManagerFS  = new FullscreenManager(this);
		this->mManagerMat = new MaterialManager(this);

		this->mLogger->Log("Voodoo Core: Core started successfully.\n");
	}

	Core::~Core()
	{
		this->mLogger->Log("Voodoo Core: Stopping...\n");

		if ( cgIsContext(this->mCGContext) )
		{
			cgDestroyContext(this->mCGContext);
		}
		if ( this->mLogger )
		{
			delete this->mLogger;
		}
	}

	Shader * Core::CreateShader(std::string filename, char ** args)
	{
		CGEffectMap::iterator CGEffect = this->mCGEffects.find(filename);
		if ( CGEffect != this->mCGEffects.end() )
		{
			return new Shader(this, CGEffect->second);
		} else {
			// Load the shader
			return new Shader(this, filename);
		}
	}

	CGcontext Core::GetCGContext()
	{
		return this->mCGContext;
	}

	Adapter * Core::GetAdapter()
	{
		return this->mAdapter;
	}

	Logger * Core::GetLog()
	{
		return this->mLogger;
	}

	void Core::SetAdapter(Adapter * adapter)
	{
		if ( this->mAdapter )
		{
			Throw("Voodoo Core: Attempted to set adapter when one is already set.", this);
		}

		this->mAdapter = adapter;
	}

	Texture * Core::CreateTexture(std::string name, void * data)
	{
		TextureMap::iterator textureEntry = this->mTextures.find(name);
		if ( textureEntry != this->mTextures.end() )
		{
			Throw("Voodoo Core: Trying to register a texture with a duplicate name.", this);
		} else {
			Texture * texture = new Texture(data, name);
			this->mTextures[name] = texture;
			return texture;
		}
	}

	Parameter * Core::CreateParameter(std::string name, bool type)
	{
		ParameterMap::iterator paramEntry = this->mParameters.find(name);
		if ( paramEntry != this->mParameters.end() )
		{
			Throw("Voodoo Core: Trying to create parameter with a duplicate name.", this);
		} else {
			CGparameter cgparameter;
			if ( type )
			{
				cgparameter = cgCreateParameter(this->mCGContext, CG_SAMPLER2D);
			} else {
				cgparameter = cgCreateParameter(this->mCGContext, CG_FLOAT4);
			}
			Parameter * parameter = new Parameter(cgparameter);
			return parameter;
		}
	}
		
	void Core::CGErrorHandler(CGcontext context, CGerror error, void * core)
	{
		Core * me = reinterpret_cast<Core*>(core);
		me->mLogger->Format("Voodoo Core: CG error: %s\n").With(cgGetErrorString(error)).Done();
	}
}